﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;

namespace PhysicsSimulator.Game.MayBanDa
{
    public partial class CatapultGameplay : PhoneApplicationPage
    {
        ContentManager contentManager;
        GameTimer timer;
        SpriteBatch spriteBatch;

        UIElementRenderer elementRenderer;

        InputState input = new InputState();

        #region Fields
        // Texture Members
        Texture2D foregroundTexture;
        Texture2D cloud1Texture;
        Texture2D cloud2Texture;
        Texture2D mountainTexture;
        Texture2D skyTexture;
        Texture2D hudBackgroundTexture;
        Texture2D ammoTypeNormalTexture;
        Texture2D ammoTypeSplitTexture;
        Texture2D windArrowTexture;
        Texture2D defeatTexture;
        Texture2D victoryTexture;
        Texture2D blankTexture;
        SpriteFont hudFont;

        // Rendering members
        Vector2 cloud1Position;
        Vector2 cloud2Position;

        Vector2 playerOneHUDPosition;
        Vector2 playerTwoHUDPosition;
        Vector2 windArrowPosition;
        Vector2 playerOneHealthBarPosition;
        Vector2 playerTwoHealthBarPosition;
        Vector2 healthBarFullSize;

        // Gameplay members
        Human playerOne;
        Player playerTwo;
        Vector2 wind;
        bool changeTurn;
        bool isFirstPlayerTurn;
        bool isTwoHumanPlayers;
        bool gameOver;
        Random random;
        const int minWind = 0;
        const int maxWind = 10;

        // Helper members
        bool isDragging;
        #endregion

        public CatapultGameplay()
        {
            InitializeComponent();

            contentManager = (Application.Current as App).Content;

            timer = new GameTimer();
            timer.UpdateInterval = TimeSpan.FromTicks(333333);
            timer.Update += timer_Update;
            timer.Draw += timer_Draw;

            LayoutUpdated += CatapultGameplay_LayoutUpdated;

            TouchPanel.EnabledGestures = GestureType.FreeDrag |
                GestureType.DragComplete |
                GestureType.Tap;

            random = new Random();
        }

        void CatapultGameplay_LayoutUpdated(object sender, EventArgs e)
        {
            if (ActualWidth == 0 || ActualHeight == 0)
                return;

            // see if we already have the right sized renderer
            if (elementRenderer != null &&
                elementRenderer.Texture != null &&
                elementRenderer.Texture.Width == (int)ActualWidth &&
                elementRenderer.Texture.Height == (int)ActualHeight)
            {
                return;
            }

            // dispose the current renderer
            if (elementRenderer != null)
                elementRenderer.Dispose();

            // create the renderer
            elementRenderer = new UIElementRenderer(LayoutRoot, (int)ActualWidth, (int)ActualHeight);
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            isTwoHumanPlayers = false;//default

            string msg = "";
            if (NavigationContext.QueryString.TryGetValue("msg", out msg))
            {
                int mode = int.Parse(msg);
                if (mode == 1)
                    isTwoHumanPlayers = true;
            }

            

            SharedGraphicsDeviceManager.Current.GraphicsDevice.SetSharingMode(true);

            spriteBatch = new SpriteBatch(SharedGraphicsDeviceManager.Current.GraphicsDevice);
            //load content
            foregroundTexture = contentManager.Load<Texture2D>("Images/Textures/Backgrounds/gameplay_screen");
            cloud1Texture = contentManager.Load<Texture2D>("Images/Textures/Backgrounds/cloud1");
            cloud2Texture = contentManager.Load<Texture2D>("Images/Textures/Backgrounds/cloud2");
            mountainTexture = contentManager.Load<Texture2D>("Images/Textures/Backgrounds/mountain");
            skyTexture = contentManager.Load<Texture2D>("Images/Textures/Backgrounds/sky");
            defeatTexture = contentManager.Load<Texture2D>("Images/Textures/Backgrounds/defeat");
            victoryTexture = contentManager.Load<Texture2D>("Images/Textures/Backgrounds/victory");
            hudBackgroundTexture = contentManager.Load<Texture2D>("Images/Textures/HUD/hudBackground");
            windArrowTexture = contentManager.Load<Texture2D>("Images/Textures/HUD/windArrow");
            ammoTypeNormalTexture = contentManager.Load<Texture2D>("Images/Textures/HUD/ammoTypeNormal");
            ammoTypeSplitTexture = contentManager.Load<Texture2D>("Images/Textures/HUD/ammoTypeSplit");
            blankTexture = contentManager.Load<Texture2D>("Images/Textures/Backgrounds/blank");
            // Load font
            hudFont = contentManager.Load<SpriteFont>("Fonts/HUDFont");

            // Define initial cloud position
            cloud1Position = new Vector2(224 - cloud1Texture.Width, 32);
            cloud2Position = new Vector2(64, 90);

            // Define initial HUD positions
            playerOneHUDPosition = new Vector2(7, 7);
            playerTwoHUDPosition = new Vector2(613, 7);
            windArrowPosition = new Vector2(345, 46);
            Vector2 healthBarOffset = new Vector2(25, 82);
            playerOneHealthBarPosition = playerOneHUDPosition + healthBarOffset;
            playerTwoHealthBarPosition = playerTwoHUDPosition + healthBarOffset;
            healthBarFullSize = new Vector2(130, 20);

            // Initialize human & AI players
            playerOne = new Human(spriteBatch, PlayerSide.Left);
            playerOne.Init(contentManager);
            playerOne.Name = "Player" + (isTwoHumanPlayers ? " 1" : "");

            if (isTwoHumanPlayers)
            {
                playerTwo = new Human(spriteBatch, PlayerSide.Right);
                playerTwo.Init(contentManager);
                playerTwo.Name = "Player 2";
            }
            else
            {
                playerTwo = new AI(spriteBatch);
                playerTwo.Init(contentManager);
                playerTwo.Name = "Phone";
            }

            // Identify enemies
            playerOne.Enemy = playerTwo;
            playerTwo.Enemy = playerOne;

            Start();

            timer.Start();
        }

       

        protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
        {
            SharedGraphicsDeviceManager.Current.GraphicsDevice.SetSharingMode(false);
            timer.Stop();
        }

        void timer_Draw(object sender, GameTimerEventArgs e)
        {
            SharedGraphicsDeviceManager.Current.GraphicsDevice.Clear(Color.CornflowerBlue);
            spriteBatch.Begin();
            DrawBackground();
            DrawPlayerTwo(e);
            DrawPlayerOne(e);
            DrawHud();
            spriteBatch.End();
        }

        void timer_Update(object sender, GameTimerEventArgs gameTime)
        {
            input.Update();
            HandleInput(input);
            float elapsed = (float)gameTime.ElapsedTime.TotalSeconds;

            // Check it one of the players reached 5 and stop the game
            if ((playerOne.Catapult.GameOver || playerTwo.Catapult.GameOver) &&
                (gameOver == false))
            {
                gameOver = true;

                if (playerOne.Score > playerTwo.Score)
                {
                    AudioManager.PlaySound("gameOver_Win");
                }
                else
                {
                    AudioManager.PlaySound("gameOver_Lose");
                }

                return;
            }

            // If Reset flag raised and both catapults are not animating - 
            // active catapult finished the cycle, new turn!
            if ((playerOne.Catapult.CurrentState == CatapultState.Reset ||
                playerTwo.Catapult.CurrentState == CatapultState.Reset) &&
                !(playerOne.Catapult.AnimationRunning ||
                playerTwo.Catapult.AnimationRunning))
            {
                changeTurn = true;

                if (playerOne.IsActive == true) //Last turn was a left player turn?
                {
                    playerOne.IsActive = false;
                    playerTwo.IsActive = true;
                    isFirstPlayerTurn = false;
                    playerOne.Catapult.CurrentState = CatapultState.Idle;
                    if (!isTwoHumanPlayers)
                        playerTwo.Catapult.CurrentState = CatapultState.Aiming;
                    else
                        playerTwo.Catapult.CurrentState = CatapultState.Idle;
                }
                else //It was an right player turn
                {
                    playerOne.IsActive = true;
                    playerTwo.IsActive = false;
                    isFirstPlayerTurn = true;
                    playerTwo.Catapult.CurrentState = CatapultState.Idle;
                    playerOne.Catapult.CurrentState = CatapultState.Idle;
                }
            }

            if (changeTurn)
            {
                // Update wind
                wind = new Vector2(random.Next(-1, 2),
                    random.Next(minWind, maxWind + 1));

                // Set new wind value to the players and 
                playerOne.Catapult.Wind = playerTwo.Catapult.Wind =
                    wind.X > 0 ? wind.Y : -wind.Y;
                changeTurn = false;
            }

            // Update the players
            playerOne.Update(gameTime);
            playerTwo.Update(gameTime);

            // Updates the clouds position
            UpdateClouds(elapsed);
        }

        #region Input
        /// <summary>
        /// Input helper method provided by GameScreen.  Packages up the various input
        /// values for ease of use.
        /// </summary>
        /// <param name="input">The state of the gamepads</param>
        public void HandleInput(InputState input)
        {
            if (input == null)
                throw new ArgumentNullException("input");

            if (gameOver)
            {
                if (input.IsPauseGame(null))
                {
                    FinishCurrentGame();
                }

                foreach (GestureSample gestureSample in input.Gestures)
                {
                    if (gestureSample.GestureType == GestureType.Tap)
                    {
                        FinishCurrentGame();
                    }
                }

                return;
            }

            if (input.IsPauseGame(null))
            {
                //PauseCurrentGame();
            }
            else if (isFirstPlayerTurn &&
                (playerOne.Catapult.CurrentState == CatapultState.Idle ||
                    playerOne.Catapult.CurrentState == CatapultState.Aiming))
            {
                // Read all available gestures
                foreach (GestureSample gestureSample in input.Gestures)
                {
                    if (gestureSample.GestureType == GestureType.FreeDrag)
                        isDragging = true;
                    else if (gestureSample.GestureType == GestureType.DragComplete)
                        isDragging = false;

                    playerOne.HandleInput(gestureSample);
                }
            }
            else if (isTwoHumanPlayers && !isFirstPlayerTurn &&
                (playerTwo.Catapult.CurrentState == CatapultState.Idle ||
                    playerTwo.Catapult.CurrentState == CatapultState.Aiming))
            {
                // Read all available gestures
                foreach (GestureSample gestureSample in input.Gestures)
                {
                    if (gestureSample.GestureType == GestureType.FreeDrag)
                        isDragging = true;
                    else if (gestureSample.GestureType == GestureType.DragComplete)
                        isDragging = false;

                    (playerTwo as Human).HandleInput(gestureSample);
                }
            }
        }
        #endregion

        #region Input Helpers
        /// <summary>
        /// Finish the current game
        /// </summary>
        private void FinishCurrentGame()
        {
            //ExitScreen();
        }

        /// <summary>
        /// Pause the current game
        /// </summary>
        private void PauseCurrentGame()
        {
            //var pauseMenuBackground = new BackgroundScreen();

            //if (isDragging)
            //{
            //    isDragging = false;
            //    playerOne.Catapult.CurrentState = CatapultState.Idle;

            //    if (isTwoHumanPlayers)
            //        playerTwo.Catapult.CurrentState = CatapultState.Idle;
            //}

            //ScreenManager.AddScreen(pauseMenuBackground, null);
            //ScreenManager.AddScreen(new PauseScreen(pauseMenuBackground,
            //    playerOne, playerTwo), null);
        }
        #endregion

        #region Update Helpers
        private void UpdateClouds(float elapsedTime)
        {
            // Move the clouds according to the wind
            int windDirection = wind.X > 0 ? 1 : -1;

            cloud1Position += new Vector2(24.0f, 0.0f) * elapsedTime *
                windDirection * wind.Y;
            if (cloud1Position.X > SharedGraphicsDeviceManager.Current.GraphicsDevice.Viewport.Width)
                cloud1Position.X = -cloud1Texture.Width * 2.0f;
            else if (cloud1Position.X < -cloud1Texture.Width * 2.0f)
                cloud1Position.X = SharedGraphicsDeviceManager.Current.GraphicsDevice.Viewport.Width;

            cloud2Position += new Vector2(16.0f, 0.0f) * elapsedTime *
                windDirection * wind.Y;
            if (cloud2Position.X > SharedGraphicsDeviceManager.Current.GraphicsDevice.Viewport.Width)
                cloud2Position.X = -cloud2Texture.Width * 2.0f;
            else if (cloud2Position.X < -cloud2Texture.Width * 2.0f)
                cloud2Position.X = SharedGraphicsDeviceManager.Current.GraphicsDevice.Viewport.Width;
        }
        #endregion
       
        #region Draw Helpers
        /// <summary>
        /// Draws the player's catapult
        /// </summary>
        void DrawPlayerOne(GameTimerEventArgs gameTime)
        {
            if (!gameOver)
                playerOne.Draw(gameTime);
        }

        /// <summary>
        /// Draws the AI's catapult
        /// </summary>
        void DrawPlayerTwo(GameTimerEventArgs gameTime)
        {
            if (!gameOver)
                playerTwo.Draw(gameTime);
        }

        /// <summary>
        /// Draw the sky, clouds, mountains, etc. 
        /// </summary>
        private void DrawBackground()
        {
            // Draw the Sky
            spriteBatch.Draw(skyTexture, Vector2.Zero, Color.White);

            // Draw Cloud #1
            spriteBatch.Draw(cloud1Texture,
                cloud1Position, Color.White);

            // Draw the Mountain
            spriteBatch.Draw(mountainTexture,
                Vector2.Zero, Color.White);

            // Draw Cloud #2
            spriteBatch.Draw(cloud2Texture,
                cloud2Position, Color.White);

            // Draw the Castle, trees, and foreground 
            spriteBatch.Draw(foregroundTexture,
                Vector2.Zero, Color.White);
        }

        /// <summary>
        /// Draw the HUD, which consists of the score elements and the GAME OVER tag.
        /// </summary>
        void DrawHud()
        {
            if (gameOver)
            {
                Texture2D texture = victoryTexture;
                string winMessage = "";
                if (playerOne.Score > playerTwo.Score)
                {
                    winMessage = "Player 1 Wins!";
                }
                else
                {
                    if (!isTwoHumanPlayers)
                        texture = defeatTexture;

                    winMessage = "Player 2 Wins!";
                }
                
                spriteBatch.Draw(
                    texture,
                    new Vector2(SharedGraphicsDeviceManager.Current.GraphicsDevice.Viewport.Width / 2 - texture.Width / 2,
                                SharedGraphicsDeviceManager.Current.GraphicsDevice.Viewport.Height / 2 - texture.Height / 2),
                    Color.White);

                if (isTwoHumanPlayers)
                {
                    Vector2 size = hudFont.MeasureString(winMessage);
                    DrawString(hudFont, winMessage,
                        new Vector2(SharedGraphicsDeviceManager.Current.GraphicsDevice.Viewport.Width / 2 - size.X / 2,
                            SharedGraphicsDeviceManager.Current.GraphicsDevice.Viewport.Height / 2 - texture.Height / 2 + 100),
                        Color.Red);
                }
            }
            else
            {
                // Draw Player Hud
                spriteBatch.Draw(hudBackgroundTexture,
                    playerOneHUDPosition, Color.White);
                spriteBatch.Draw(GetWeaponTexture(playerOne),
                    playerOneHUDPosition + new Vector2(33, 35), Color.White);
                DrawString(hudFont, playerOne.Score.ToString(),
                    playerOneHUDPosition + new Vector2(123, 35), Color.White);
                DrawString(hudFont, playerOne.Name,
                    playerOneHUDPosition + new Vector2(40, 1), Color.Blue);

                Rectangle rect = new Rectangle((int)playerOneHealthBarPosition.X, (int)playerOneHealthBarPosition.Y,
                    (int)healthBarFullSize.X * playerOne.Health / 100, (int)healthBarFullSize.Y);
                Rectangle underRect = new Rectangle(rect.X, rect.Y, rect.Width + 1, rect.Height + 1);
                spriteBatch.Draw(blankTexture, underRect, Color.Black);
                spriteBatch.Draw(blankTexture, rect, Color.Blue);

                // Draw Computer Hud
                spriteBatch.Draw(hudBackgroundTexture,
                    playerTwoHUDPosition, Color.White);
                spriteBatch.Draw(GetWeaponTexture(playerTwo),
                    playerTwoHUDPosition + new Vector2(33, 35), Color.White);
                DrawString(hudFont, playerTwo.Score.ToString(),
                    playerTwoHUDPosition + new Vector2(123, 35), Color.White);
                DrawString(hudFont, playerTwo.Name,
                    playerTwoHUDPosition + new Vector2(40, 1), Color.Red);

                rect = new Rectangle((int)playerTwoHealthBarPosition.X, (int)playerTwoHealthBarPosition.Y,
                    (int)healthBarFullSize.X * playerTwo.Health / 100, (int)healthBarFullSize.Y);
                underRect = new Rectangle(rect.X, rect.Y, rect.Width + 1, rect.Height + 1);
                spriteBatch.Draw(blankTexture, underRect, Color.Black);
                spriteBatch.Draw(blankTexture, rect, Color.Red);

                // Draw Wind direction
                string text = "Wind";
                Vector2 size = hudFont.MeasureString(text);
                Vector2 windarrowScale = new Vector2(wind.Y / 10, 1);
                spriteBatch.Draw(windArrowTexture,
                    windArrowPosition, null, Color.White, 0, Vector2.Zero,
                    windarrowScale, wind.X > 0
                    ? SpriteEffects.None : SpriteEffects.FlipHorizontally, 0);

                DrawString(hudFont, text,
                    windArrowPosition - new Vector2(0, size.Y), Color.Black);
                if (wind.Y == 0)
                {
                    text = "NONE";
                    DrawString(hudFont, text, windArrowPosition, Color.Black);
                }

                //if (isFirstPlayerTurn)
                //{
                //    // Prepare first player prompt message
                //    text = !isDragging ?
                //        (isTwoHumanPlayers ? "Player 1, " : "") + "Drag Anywhere to Fire" : "Release to Fire!";
                //    size = hudFont.MeasureString(text);
                //}
                //else
                //{
                //    // Prepare second player prompt message
                //    if (isTwoHumanPlayers)
                //        text = !isDragging ? "Player 2, Drag Anywhere to Fire!" : "Release to Fire!";
                    

                //    size = hudFont.MeasureString(text);
                //}

                //DrawString(hudFont, text,
                //    new Vector2(
                //        SharedGraphicsDeviceManager.Current.GraphicsDevice.Viewport.Width / 2 - size.X / 2,
                //        SharedGraphicsDeviceManager.Current.GraphicsDevice.Viewport.Height - size.Y),
                //        Color.Green);
            }
        }

        /// <summary>
        /// Returns the texture appropriate for the player's current weapon
        /// </summary>
        /// <param name="player">The player for which to get the texture</param>
        /// <returns>Ammo texture to draw in the HUD</returns>
        private Texture2D GetWeaponTexture(Player player)
        {
            switch (player.Weapon)
            {
                case WeaponType.Normal:
                    return ammoTypeNormalTexture;
                case WeaponType.Split:
                    return ammoTypeSplitTexture;
                default:
                    throw new ArgumentException("Player has invalid weapon type",
                        "player");
            }
        }

        /// <summary>
        /// A simple helper to draw shadowed text.
        /// </summary>
        void DrawString(SpriteFont font, string text, Vector2 position, Color color)
        {
            spriteBatch.DrawString(font, text,
                new Vector2(position.X + 1, position.Y + 1), Color.Black);
            spriteBatch.DrawString(font, text, position, color);
        }

        /// <summary>
        /// A simple helper to draw shadowed text.
        /// </summary>
        void DrawString(SpriteFont font, string text, Vector2 position, Color color, float fontScale)
        {
            spriteBatch.DrawString(font, text, new Vector2(position.X + 1,
                position.Y + 1), Color.Black, 0, new Vector2(0, font.LineSpacing / 2),
                fontScale, SpriteEffects.None, 0);
            spriteBatch.DrawString(font, text, position, color, 0,
                new Vector2(0, font.LineSpacing / 2), fontScale, SpriteEffects.None, 0);
        }
        #endregion

        #region Gameplay Helpers
        /// <summary>
        /// Starts a new game session, setting all game states to initial values.
        /// </summary>
        void Start()
        {
            // Set initial wind direction
            wind = Vector2.Zero;
            isFirstPlayerTurn = false;
            changeTurn = true;
            playerTwo.Catapult.CurrentState = CatapultState.Reset;
        }
        #endregion
    }
}